
import { AutoComplete, Select, Table, Space, Checkbox, Input, Form, Popover, Radio, Tag } from 'antd';
import styles from './style.less';
const { Option } = Select;
import { useEffect, useState } from 'react';
import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
import { DragOutlined, ImportOutlined } from '@ant-design/icons';
import { PARAM_TYPE, DATA_TYPE, JSON_SUB_TYPE, RAW_SUB_TYPE } from '@/consts/api'
import TextButton from '@/components/TextButton'
import CodeEditor, { CodeView } from '@/components/CodeEditor'
import IdUtils from '@/utils/IdUtils'
import ObjectsUtils from '@/utils/ObjectsUtils'
const DragHandle = sortableHandle(() => <DragOutlined style={{ cursor: 'grab' }} />);
const SortableItem = sortableElement(props => <tr className={styles.row} {...props} />);
const SortableContainer = sortableContainer(props => <tbody {...props} />);

const defaultValuesOptions = [{
    value: "0"
}, {
    value: "Null"
}, {
    value: "EmptyString"
}]

const CheckboxValue = ({ value, onChange, children }) => {

    return <Checkbox checked={value} onChange={(e) => {
        if (onChange) {
            onChange(e.target.checked)
        }
    }}>{children}</Checkbox>
}

const ApiParamEditTable = (props) => {
    const {
        value,
        defaultValue,
        className,
        onChange,
        hasChildren = true,
        enableTypes = PARAM_TYPE,
        actions,
        mode = "edit",
        dragable = true,
        operation = true,
        bordered
    } = props;

    useEffect(() => {
        let initValue = defaultValue?.fields;
        if (!initValue) {
            initValue = [];
        }
        if (initValue.length === 0 && mode === 'edit') {
            initValue.push(getDefaultField())
        }
        setRealValue(initValue)
        // console.log("--reloadValue", initValue)
    }, [])


    useEffect(() => {
        // console.log("--reloadValue", value)
        if (value) {
            let unionValue = value?.fields;
            if (!unionValue) {
                unionValue = [];
            }
            if (unionValue.length === 0 && mode === 'edit') {
                unionValue.push(getDefaultField())
            }
            setRealValue(unionValue)
        }
    }, [value])

    const [realValue, setRealValue] = useState([]);
    const [formFieldData, setFormFieldData] = useState({});
    const [expendRows, setExpendRows] = useState([])
    const [form] = Form.useForm();



    useEffect(() => {
        // console.log("--reloadrealValue", realValue)
        if (realValue) {
            let expendRows = []
            loopRealValue(realValue, (item) => {
                formFieldData[item.id] = item;
                if (item.fields) {
                    expendRows.push(item.id)
                }
            })
            // console.log("formFieldData", formFieldData)
            setFormFieldData({
                ...formFieldData
            })
            setExpendRows(expendRows)
        }
    }, [realValue])

    useEffect(() => {
        // console.log("--reloadrealformFieldData",formFieldData)
        if (formFieldData) {
            form.resetFields();
        }
    }, [formFieldData])

    const convertToDataField = (realValue) => {

        return realValue.map(item => {
            let fields = null;
            if (item.fields) {
                fields = convertToDataField(item.fields)
            }
            // console.log(item)
            return {
                name: item.name,
                isRequire: item.isRequire,
                type: item.type,
                remark: item.remark,
                defaultValue: item.defaultValue,
                id: item.id,
                fields: fields
            }
        })
    }

    const loopRealValue = (data, callback, parent) => {
        if (data) {
            data.forEach((item) => {
                callback(item, parent);
                if (item.fields) {
                    loopRealValue(item.fields, callback, item)
                }
            })
        }
    }

    const onValuesChange = (record) => {
        // console.log(record); 
        loopRealValue(realValue, (item, parent) => {
            if (record[item.id]) {
                ObjectsUtils.copyProperties(record[item.id], item)
                formFieldData[item.id] = {
                    ...item,
                    ...record[item.id]
                }
                if (record[item.id].type) {
                    setFormFieldData({ ...formFieldData })
                }
            }
        }, null)

        if (onChange) {
            // console.log("onChange", realValue)
            onChange({
                fields: convertToDataField(realValue)
            })
        }
        // console.log(realValue)
        // setRealValue([...realValue])
    }

    const addDown = (record, index) => {
        loopRealValue(realValue, (item, parent) => {
            if (item.id === record.id) {
                if (parent) {
                    console.log(parent)
                    parent.fields.splice(index + 1, 0, getDefaultField())
                } else {
                    realValue.splice(index + 1, 0, getDefaultField())
                }
                setRealValue([...realValue])
            }
        }, null)
    }

    const deleteItem = (record, index) => {
        loopRealValue(realValue, (item, parent) => {
            if (item.id === record.id) {
                if (parent) {
                    parent.fields.splice(index, 1)
                } else {
                    realValue.splice(index, 1)
                    if (realValue.length === 0) {
                        realValue.push(getDefaultField())
                    }
                }
                setRealValue([...realValue])
            }
        }, null)
    }

    const getDefaultField = () => {
        return {
            id: IdUtils.uuid(),
            name: "",
            type: "string"
        }
    }
    const addUp = (record, index) => {
        loopRealValue(realValue, (item, parent) => {
            if (item.id === record.id) {
                if (parent) {
                    if (index === 0) {
                        parent.fields = [getDefaultField(), ...parent.fields]
                    } else {
                        parent.fields.splice(index, 0, getDefaultField())
                    }
                    setRealValue([...realValue])
                } else {
                    if (index === 0) {
                        setRealValue([getDefaultField(), ...realValue])
                    } else {
                        realValue.splice(index, 0, getDefaultField())
                        setRealValue([...realValue])
                    }
                }
            }
        }, null)

    }

    const addChildren = (record) => {
        let newField = getDefaultField();
        if (record.fields) {
            record.fields.push(newField)
        } else {
            record.fields = [];
            record.fields.push(newField)
        }
        setRealValue([...realValue])
        setExpendRows([...expendRows, newField])
    }


    const columns = [
        {
            title: <DragOutlined />,
            dataIndex: 'sort',
            align: "center",
            width: "40px",
            className: styles.dragVisible,
            render: () => <DragHandle />,
        },
        {
            title: '名称',
            dataIndex: 'name',
            className: styles.columns,
            onCell: (record) => ({
                record,
                dataIndex: 'name',
                title: 'name',
                render: (text, record) => <Input ></Input>,
            }),
        },
        {
            title: '类型',
            dataIndex: 'type',
            width: '84px',
            className: styles.columns,

            onCell: (record) => ({
                record,
                dataIndex: 'type',
                title: 'type',
                render: (text, record) => <Select dropdownStyle={{ zIndex: 10000 }}     >
                    {enableTypes.map(type => <Option key={type} value={type}>{type}</Option>)}
                </Select>,
            }),
        },
        {
            title: '必填',
            align: "center",
            dataIndex: 'isRequire',
            width: '48px',
            className: styles.columns,
            onCell: (record) => ({
                record,
                dataIndex: 'isRequire',
                title: 'isRequire',
                render: (text, record) => <CheckboxValue ></CheckboxValue>,

            }),
        },
        {
            title: '说明',
            dataIndex: 'remark',
            className: styles.columns,
            onCell: (record) => ({
                record,
                dataIndex: 'remark',
                title: 'remark',
                render: (text, record) => <Input ></Input>,

            }),
        },
        {
            title: '默认值',
            dataIndex: 'defaultValue',
            className: styles.columns,
            onCell: (record) => ({
                record,
                dataIndex: 'defaultValue',
                title: 'defaultValue',
                render: (text, record) => <AutoComplete options={defaultValuesOptions} >
                    <Input ></Input>
                </AutoComplete>,
            }),
        },
        {
            title: '操作',
            dataIndex: 'operation',
            className: styles.actionColumns,
            render: (text, record, index) => [
                <Popover
                    zIndex={10000}
                    key="addAction"
                    placement="bottom"
                    content={
                        <div className={styles.action}>
                            <TextButton key="addUp" onClick={() => addUp(record, index)}>上方</TextButton>
                        </div>
                    }>
                    <a key="addDown" onClick={() => addDown(record, index)}>添加</a>
                </Popover>,
                hasChildren && (formFieldData[record.id]?.type === 'object' || formFieldData[record.id]?.type === 'array') && <TextButton key="inner" onClick={() => addChildren(record)}>子参数</TextButton>,
                < TextButton key="delete" onClick={() => { deleteItem(record, index) }}> 删除</TextButton >
            ],
        },
    ];

    const viewColumns = [
        {
            title: '名称',
            dataIndex: 'name',
            className: styles.columns,
        },
        {
            title: '类型',
            dataIndex: 'type',
            width: '84px',
            className: styles.columns,
        },
        {
            title: '必填',
            align: "center",
            dataIndex: 'isRequire',
            width: '48px',
            className: styles.columns,
            render: (text, record) => record.isRequire ? "是" : "否"
        },
        {
            title: '说明',
            dataIndex: 'remark',
            className: styles.columns,
        },
        {
            title: '默认值',
            dataIndex: 'defaultValue',
            className: styles.columns,
        }
    ];


    const onExpandedRowsChange = (expandedRows) => {
        console.log(expandedRows)
        setExpendRows([...expandedRows])
    }


    const arrayMove = (list, oldIndex, newIndex) => {
        let item = list[oldIndex];
        list.splice(oldIndex, 1)
        list.splice(newIndex, 0, item)
    }

    const onSortEnd = ({ oldIndex, newIndex }) => {
        if (oldIndex !== newIndex) {
            console.log('Sorted items: ', oldIndex, newIndex);
            arrayMove(realValue, oldIndex, newIndex)
            // const newData = arrayMove([].concat(paramData), oldIndex, newIndex).filter(el => !!el);
            setRealValue([...realValue])
        }
    };

    const draggableContainer = props => (
        <SortableContainer
            useDragHandle
            disableAutoscroll
            helperClass={styles.rowDragging}
            onSortEnd={onSortEnd}
            {...props}
        />
    );

    const draggableBodyRow = ({ className, style, ...restProps }) => {
        // function findIndex base on Table rowKey props and should always be a right array index
        const index = realValue.findIndex(x => x.id === restProps['data-row-key']);
        return <SortableItem index={index} {...restProps} />;
    };

    const checkName = (data, name) => {
        // console.log(data,name)  
        let id = data.field.split(".")[0];
        let isSameName = [false]
        loopRealValue(realValue, (item, parent) => {
            if (item.id === id) {
                // console.log(item.id, id,  parent)
                if (parent) {
                    parent.fields.forEach(f => {
                        if (f.id !== id && f.name === name) {
                            isSameName[0] = true;
                        }
                    })
                } else {
                    realValue.forEach(f => {
                        if (f.id !== id && f.name === name) {
                            isSameName[0] = true;
                        }
                    })
                }

            }
        })
        if (isSameName[0]) {
            return Promise.reject(new Error('名称不能重复'));
        } else {
            return Promise.resolve();
        }
    }

    const editableCell = ({ children, record, render, dataIndex, ...restProps }) => {
        if (!record || mode === "view") {
            return <td {...restProps}>{children}</td>
        }
        if (dataIndex === "name") {
            return <td {...restProps}>
                {children[0]}
                <Form.Item
                    style={{ margin: 0 }}
                    name={[record.id, dataIndex]}
                    rules={[
                        {
                            validator: checkName,
                        },
                    ]}
                >
                    {render()}
                </Form.Item>
            </td>
        }
        return <td {...restProps}>
            <Form.Item
                style={{ margin: 0 }}
                name={[record.id, dataIndex]}
            >
                {render()}
            </Form.Item>
        </td>
    }

    const renderActions = () => {
        let actionsButtons = [];
        if (actions) {
            actionsButtons = [...actions]
        } else {
            actionsButtons = ["import", "relateModel"]
        }
        actionsButtons = actionsButtons.map(act => {
            if (act === "import") {
                return <TextButton key="import"><ImportOutlined />导入</TextButton>
            }
            if (act === "relateModel") {
                return <TextButton key="relateModel"><ImportOutlined />关联数据模型</TextButton>
            }
            return act;
        })
        return actionsButtons
    }
    const renderColumns = () => {
        if (mode === "view") {
            return viewColumns;
        }
        let renderColumns = [...columns];
        if (!dragable) {
            renderColumns = renderColumns.filter(item => item.dataIndex !== "sort")
        }
        if (!operation) {
            renderColumns = renderColumns.filter(item => item.dataIndex !== "operation")
        }
        return renderColumns;
    }

    // console.log("--reload", realValue)
    return <div className={className}>
        {mode === "edit" &&
            <Space className={styles.rootOpertions}>
                {renderActions()}
            </Space>
        }
        <Form form={form} onValuesChange={onValuesChange} component={false} initialValues={formFieldData}>
            <Table columns={renderColumns()}
                dataSource={realValue}
                pagination={false}
                className={styles.tableContext}
                expandable={{
                    indentSize: mode === "edit" ? 8 : 16,
                    expandedRowKeys: expendRows,
                    expandIconColumnIndex: mode === "edit" ? 1 : 0,
                    defaultExpandAllRows: true,
                    childrenColumnName: "fields",
                    onExpandedRowsChange: onExpandedRowsChange
                }}
                size="small"
                rowKey="id"
                bordered={bordered}
                components={{
                    body: {
                        wrapper: draggableContainer,
                        row: draggableBodyRow,
                        cell: editableCell,
                    },
                }}
            >
            </Table>
        </Form>

    </div>
}


const ComplexParamEditTable = (props) => {

    const {
        value,
        defaultValue,
        bordered,
        enableTypes,
        onChange,
        hasChildren = true
    } = props;

    useEffect(() => {
        let unionValue = value || defaultValue;
        if (!unionValue) {
            unionValue = {
                type: "json",
                objSubType: "object",
                subType: "json"
            }
        }
        setRealValue(unionValue)

    }, [value, defaultValue])

    const [realValue, setRealValue] = useState({});

    const onTypeChange = (e) => {
        // console.log(e.target.value)
        let newValue = {
            ...realValue,
            type: e.target.value
        }
        if (newValue.type === "raw" && !newValue.subType) {
            newValue.subType = "json"
        }
        setRealValue(newValue)
        if (onChange) {
            onChange(newValue)
        }
    }

    const onSubTypeChange = (value) => {
        let newValue = {
            ...realValue,
            subType: value
        }
        setRealValue(newValue)
        if (onChange) {
            onChange(newValue)
        }
    }

    const onObjSubTypeChange = (value) => {
        let newValue = {
            ...realValue,
            objSubType: value
        }
        setRealValue(newValue)
        if (onChange) {
            onChange(newValue)
        }
    }

    const onContentChange = (editor, data, value) => {
        console.log(editor, data, value)
        let newValue = {
            ...realValue,
            content: value
        }
        // setRealValue(newValue)
        if (onChange) {
            onChange(newValue)
        }
    }

    const onParamChange = (paramsData) => {
        let newValue = {
            ...realValue,
            ...paramsData
        }
        if (onChange) {
            onChange(newValue)
        }
    }

    const rawSubTypeRender = (
        <Select value={realValue.subType} style={{ width: 100 }} onChange={onSubTypeChange}>
            {RAW_SUB_TYPE.map(type => <Option key={type} value={type}>{type}</Option>)}
        </Select>
    )

    const jsonSubTypeRender = (
        <Select value={realValue.objSubType} style={{ width: 80 }} onChange={onObjSubTypeChange}>
            {JSON_SUB_TYPE.map(type => <Option key={type} value={type}>{type}</Option>)}
        </Select>
    )

    const renderApiEditor = () => {
        if (realValue.type === "raw" || realValue.type === "none") {
            let codeStyle = "javascript"
            if (realValue.subType === "xml" || realValue.subType === "html") {
                codeStyle = "xml"
            }
            return (<div >
                <CodeEditor
                    className={styles.code}
                    value={realValue.content}
                    onChange={onContentChange}
                    ontions={{
                        mode: codeStyle
                    }}
                >
                </CodeEditor>
            </div>)
        }
        if (realValue.type === "json" || realValue.type === "xml") {
            return <ApiParamEditTable bordered={bordered} value={realValue} onChange={onParamChange}></ApiParamEditTable>
        }

        if (realValue.type === "form_data" || realValue.type === "x_www_form_urlencoded") {
            return <ApiParamEditTable hasChildren={false} bordered={bordered} value={realValue} onChange={onParamChange}></ApiParamEditTable>
        }
    }

    return (<div>
        <div >
            <Space className={styles.dataType}>
                <Radio.Group onChange={onTypeChange} value={realValue.type}>
                    {DATA_TYPE.map(type => <Radio key={type} value={type}>{type}</Radio>)}
                </Radio.Group>
            </Space>
            <div className={styles.subType}>
                {realValue.type === "raw" && (<span>类型：{rawSubTypeRender}</span>)}
                {realValue.type === "json" && (<span>类型：{jsonSubTypeRender}</span>)}
            </div>
        </div>
        {renderApiEditor()}
    </div>)
}



const ComplexParamEditTableView = (props) => {

    const {
        value,
        defaultValue,
        bordered,
    } = props;

    const renderApiEditor = () => {
        if (value.type === "raw" || value.type === "none") {
            let codeStyle = "javascript"
            if (value.subType === "xml" || value.subType === "html") {
                codeStyle = "xml"
            }
            return (<div >
                <CodeView
                    className={styles.code}
                    value={value.content}
                    ontions={{
                        mode: codeStyle
                    }}
                >
                </CodeView>
            </div>)
        }
        return <ApiParamEditTable bordered={bordered} value={value} mode="view" bordered={bordered}></ApiParamEditTable>
    }

    return (<div>
        <Space className={styles.dataInfo} size={4}>
            <Tag color="cyan">ContentType : {value.type}</Tag>
            {value.type === "json" && <Tag color="cyan">数据结构类型 : {value.objSubType}</Tag>}
            {value.type === "raw" && <Tag color="cyan">内容格式 : {value.subType}</Tag>}
        </Space>
        {renderApiEditor()}
    </div>)
}

export { ComplexParamEditTable, ComplexParamEditTableView }
export default ApiParamEditTable;